/**
 * BaseDaoImpl.java
 * create by Lisq
 * date 2014-1-6
 */
package com.lsq.common.dao.impl;

import java.io.Serializable;
import java.util.Iterator;
import java.util.List;

import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

import com.lsq.common.dao.IBaseDao;
import com.lsq.common.page.HibernatePage;
import com.lsq.common.page.Page;

/**
 * @author Lisq
 * @param <T>
 * 
 */
@Repository(value = "baseDao")
public class BaseDaoImpl<T, ID extends Serializable> implements IBaseDao<T, ID> {
	/** from 令牌标识 */
	private static final String FROM = "from ";
	/** select 令牌标识 */
	private static final String SELECT = "select ";
	/** distinct 令牌标识 */
	private static final String DISTINCT = "distinct ";
	/** group by 令牌标识 */
	private static final String GROUPBY = "group by ";
	/** order by 令牌标识 */
	private static final String ORDERBY = "order by ";
	/** 缺省每页显示行数. */
	private int DEFAUT_PAGESIZE = 10;

	public int getDefaultSize() {
		return this.DEFAUT_PAGESIZE;
	}

	@Autowired
	private SessionFactory sessionFactory;

	public Session getSession() {
		return sessionFactory.getCurrentSession();
	}

	@Override
	public void save(T entity) {
		getSession().saveOrUpdate(entity);
		getSession().flush();
	}

	@Override
	public void delete(T entity) {
		getSession().delete(entity);
	}

	@SuppressWarnings("unchecked")
	@Override
	public T load(Class<T> entityClass, Serializable id) {
		return (T) getSession().get(entityClass, id);
	}

	@SuppressWarnings("unchecked")
	@Override
	public List<T> loadAll(Class<T> entityClass) {
		return getSession().createQuery(FROM + entityClass.getName()).list();
	}

	@SuppressWarnings("unchecked")
	@Override
	public List<T> executeSql(String queryString) {
		return getSession().createQuery(queryString).list();
	}

	@SuppressWarnings("unchecked")
	@Override
	public List<T> executeSql(String queryString, Object[] values) {
		Query query = getSession().createQuery(queryString);
		for (int i = 0; i < values.length; i++) {
			query.setParameter(i, values[i]);
		}
		return query.list();
	}

	@Override
	public Page<T> find(String queryString, int pageNumber) {
		return this.find(queryString, pageNumber, getDefaultSize());
	}

	@SuppressWarnings("unchecked")
	@Override
	public Page<T> find(String queryString, int pageNumber, int pageSize) {
		Query query = getSession()
				.createQuery(this.getCountString(queryString));
		int recordNumber = this.getRecordNumber(queryString, query.iterate());
		if (recordNumber == 0) {
			return new HibernatePage<T>();
		}
		HibernatePage<T> page = new HibernatePage<T>(pageSize, pageNumber,
				recordNumber);
		Query queryObject = getSession().createQuery(queryString);
		queryObject.setFirstResult((page.getPageNumber() - 1) * pageSize);
		queryObject.setMaxResults(pageSize);
		List<T> data = queryObject.list();
		page.setData(data);
		return page;
	}

	@Override
	public Page<T> find(String queryString, Object value, int pageNumber) {
		return this.find(queryString, value, pageNumber, getDefaultSize());
	}

	@SuppressWarnings("unchecked")
	@Override
	public Page<T> find(String queryString, Object value, int pageNumber,
			int pageSize) {
		Query query = getSession()
				.createQuery(this.getCountString(queryString));
		query.setParameter(0, value);
		int recordNumber = this.getRecordNumber(queryString, query.iterate());
		if (recordNumber == 0) {
			return new HibernatePage<T>();
		}
		HibernatePage<T> page = new HibernatePage<T>(pageSize, pageNumber,
				recordNumber);
		Query queryObject = getSession().createQuery(queryString);
		queryObject.setParameter(0, value);
		queryObject.setFirstResult((page.getPageNumber() - 1) * pageSize);
		queryObject.setMaxResults(pageSize);
		List<T> data = queryObject.list();
		page.setData(data);
		return page;
	}

	@Override
	public Page<T> find(String queryString, Object[] values, int pageNumber) {
		return this.find(queryString, values, pageNumber, getDefaultSize());
	}

	@SuppressWarnings("unchecked")
	@Override
	public Page<T> find(String queryString, Object[] values, int pageNumber,
			int pageSize) {
		Query query = getSession()
				.createQuery(this.getCountString(queryString));
		for (int i = 0; i < values.length; i++) {
			query.setParameter(i, values[i]);
		}
		int recordNumber = this.getRecordNumber(queryString, query.iterate());
		if (recordNumber == 0) {
			return new HibernatePage<T>();
		}
		HibernatePage<T> page = new HibernatePage<T>(pageSize, pageNumber,
				recordNumber);
		Query queryObject = getSession().createQuery(queryString);
		for (int i = 0; i < values.length; i++) {
			queryObject.setParameter(i, values[i]);
		}
		queryObject.setFirstResult((page.getPageNumber() - 1) * pageSize);
		queryObject.setMaxResults(pageSize);
		List<T> data = queryObject.list();
		page.setData(data);
		return page;
	}

	@SuppressWarnings("unchecked")
	@Override
	public Page<T> find(String queryString, String fieldString,
			Object[] values, int pageNumber) {
		Query query = getSession().createQuery(
				this.getCountString(SELECT + fieldString + queryString));
		for (int i = 0; i < values.length; ++i) {
			query.setParameter(i, values[i]);
		}
		int recordNumber = this.getRecordNumber(queryString, query.iterate());

		if (recordNumber == 0) {
			return new HibernatePage<T>();
		}
		HibernatePage<T> page = new HibernatePage<T>(getDefaultSize(), pageNumber,
				recordNumber);
		Query queryObject = getSession().createQuery(queryString);
		for (int i = 0; i < values.length; i++) {
			queryObject.setParameter(i, values[i]);
		}
		queryObject.setFirstResult((page.getPageNumber() - 1) * getDefaultSize());
		queryObject.setMaxResults(getDefaultSize());
		List<T> data = queryObject.list();
		page.setData(data);
		return page;
	}

	@Override
	public Page<T> putDataToPage(List<T> data) {
		return this.putDataToPage(data, 1);
	}

	@Override
	public Page<T> putDataToPage(List<T> data, int pageNumber) {
		Page<T> result = new HibernatePage<T>(100000, pageNumber, data.size());
		result.setData(data);
		return result;
	}

	/**
	 * 取得查询计划总记录数的HSQL.
	 * 
	 * @param queryString
	 *            查询数据的HSQL
	 * @return 查询总记录数的HSQL
	 */
	private String getCountString(final String queryString) {
		String countTokenString = "*";
		String targetString = queryString.toLowerCase();
		int fromPos = targetString.indexOf(FROM);
		String fromTokenString = queryString.substring((fromPos < 0) ? 0
				: fromPos);
		int orderPos = fromTokenString.indexOf(ORDERBY);
		if (orderPos > 0) {
			fromTokenString = fromTokenString.substring(0, orderPos);
		}
		if (fromPos > 0) {
			int selectPos = targetString.indexOf(SELECT);
			int distinctPos = targetString.indexOf(DISTINCT);
			if (selectPos >= 0 && distinctPos >= 0) {
				countTokenString = queryString.substring(
						selectPos + SELECT.length(), fromPos);
				String[] tokenArray = countTokenString.split(",");
				if (tokenArray.length > 0) {
					countTokenString = tokenArray[0];
				}
			}
		}
		return new StringBuffer().append("select count(")
				.append(countTokenString).append(") ").append(fromTokenString)
				.toString();
	}

	/**
	 * 获取总记录数，在兼容以往处理机制的基础上，增加对分组数据的处理
	 * 
	 * @param queryString
	 *            查询语句
	 * @param iterator
	 *            执行getCountString后返回的迭代器
	 * @return 总记录数
	 */
	private int getRecordNumber(final String queryString, Iterator<?> iterator) {
		int recordNumber = 0;
		if (queryString.indexOf(GROUPBY) > 0) {
			while (iterator.hasNext()) {
				recordNumber++;
				iterator.next();
			}
		} else if (iterator.hasNext()) {
			recordNumber = ((Long) iterator.next()).intValue();
		}
		return recordNumber;
	}
}
